﻿using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RantLEDOCR.Common
{
    public class DigitRecognizer
    {
        // 七段数码管的段定义（a, b, c, d, e, f, g）
        private readonly List<Point[]> segments = new List<Point[]>
        {
            new Point[] { new Point(3, 2), new Point(13, 2), new Point(11, 4), new Point(5, 4) }, // a
            new Point[] { new Point(14, 3), new Point(14, 13), new Point(12, 11), new Point(12, 5) }, // b
            new Point[] { new Point(14, 14), new Point(14, 24), new Point(12, 22), new Point(12, 16) }, // c
            new Point[] { new Point(3, 25), new Point(13, 25), new Point(11, 23), new Point(5, 23) }, // d
            new Point[] { new Point(2, 14), new Point(2, 24), new Point(4, 22), new Point(4, 16) }, // e
            new Point[] { new Point(2, 3), new Point(2, 13), new Point(4, 11), new Point(4, 5) }, // f
            new Point[] { new Point(3, 12), new Point(13, 12), new Point(11, 14), new Point(5, 14) } // g
        };

        // 小数点的位置定义
        private readonly Point[] decimalPoint = new Point[]
        {
            new Point(14, 26), new Point(16, 26), new Point(16, 28), new Point(14, 28)
        };

        // 数字0-9对应的段组合
        private readonly Dictionary<string, int> digitSegments = new Dictionary<string, int>
        {
            { "abcdef", 0 },
            { "bc", 1 },
            { "abdeg", 2 },
            { "abcdg", 3 },
            { "bcfg", 4 },
            { "acdfg", 5 },
            { "acdefg", 6 },
            { "abc", 7 },
            { "abcdefg", 8 },
            { "abcdfg", 9 }
        };

        public string RecognizeDigits(Mat frame)
        {
            try
            {
                // 预处理图像
                var processed = PreprocessImage(frame);
                Cv2.ImShow("new", processed);
                // 检测数码管区域和小数点区域
                var digitRegions = DetectDigitRegions(processed);

                // 识别每个数码管区域中的数字和可能的小数点
                string result = "";
                for (int i = 0; i < digitRegions.Count; i++)
                {
                    var region = digitRegions[i];
                    var digitMat = processed[region];

                    // 识别数字
                    int digit = RecognizeSingleDigit(digitMat);
                    if (digit >= 0)
                    {
                        result += digit.ToString();

                        // 检查下一个区域是否是小数点
                        bool hasDecimalPoint = false;
                        if (i < digitRegions.Count - 1)
                        {
                            var nextRegion = digitRegions[i + 1];
                            // 如果下一个区域很小，可能是小数点
                            if (nextRegion.Width < region.Width / 2 && nextRegion.Height < region.Height / 2)
                            {
                                hasDecimalPoint = true;
                                i++; // 跳过小数点区域
                            }
                        }

                        if (hasDecimalPoint)
                        {
                            result += ".";
                        }
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"识别数字时出错: {ex.Message}");
                return "Error";
            }
        }

        private Mat PreprocessImage(Mat frame)
        {
            // 转换为灰度图
            var gray = new Mat();
            Cv2.CvtColor(frame, gray, ColorConversionCodes.BGR2GRAY);

            // 高斯模糊
            var blurred = new Mat();
            Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0);

            // 二值化
            var binary = new Mat();
            Cv2.Threshold(blurred, binary, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);

            // 形态学操作：闭运算（填充空洞）
            var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
            var closed = new Mat();
            Cv2.MorphologyEx(binary, closed, MorphTypes.Close, kernel);

            return closed;
        }

        private List<Rect> DetectDigitRegions(Mat processed)
        {
            // 查找轮廓
            Cv2.FindContours(processed, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy,
                RetrievalModes.External, ContourApproximationModes.ApproxSimple);

            // 筛选数码管区域和小数点区域
            var digitRegions = new List<Rect>();
            foreach (var contour in contours)
            {
                var boundingRect = Cv2.BoundingRect(contour);

                // 根据宽高比和面积筛选数码管
                double aspectRatio = (double)boundingRect.Width / boundingRect.Height;
                double area = Cv2.ContourArea(contour);

                // 数码管区域
                if (aspectRatio >1 && aspectRatio < 2 && area > 1000)
                {
                    digitRegions.Add(boundingRect);
                }
                // 可能的小数点区域 (更小且更方)
                else if (aspectRatio > 0.7 && aspectRatio < 1.3 && area > 100 && area < 500)
                {
                    digitRegions.Add(boundingRect);
                }
            }

            return digitRegions.OrderBy(r => r.X).ToList();
        }

        private int RecognizeSingleDigit(Mat digitMat)
        {
            // 调整到标准大小
            var resized = new Mat();
            Cv2.Resize(digitMat, resized, new Size(16, 28));

            // 识别每个段的状态
            string activeSegments = "";
            for (int i = 0; i < segments.Count; i++)
            {
                // 创建掩码
                var mask = new Mat(resized.Size(), MatType.CV_8UC1, Scalar.Black);
                Cv2.FillPoly(mask, new[] { segments[i] }, Scalar.White);

                // 计算段内的白色像素比例
                var segmentRegion = new Mat();
                Cv2.BitwiseAnd(resized, resized, segmentRegion, mask);
                double whitePixels = Cv2.CountNonZero(segmentRegion);
                double totalPixels = Cv2.CountNonZero(mask);

                // 如果白色像素比例超过阈值，则认为该段是亮的
                if (whitePixels / totalPixels > 0.5)
                {
                    activeSegments += (char)('a' + i);
                }
            }

            // 匹配对应的数字
            if (digitSegments.TryGetValue(activeSegments, out int digit))
            {
                return digit;
            }

            return -1; // 无法识别
        }
    }
}
